Key management
This section provides information about key management with ProtectToolkit-J.
Key storage
The encryption adapter has the facility to store public, private, and secret keys. These keys will be stored in the non-volatile storage on the card. As well as key storage, it is also possible to store X.509 Certificates (which contain a public key). ProtectToolkit-J provides access to this storage mechanism via the JCE KeyStore API. The JCE name for this KeyStore is CRYPTOKI.
The JCE KeyStore API allows storage of a Key and an associated alias. This alias is simply a unique string which can be used to access the key. To store a key in the key store, use the setKeyEntry(). To retrieve a key, use the getKey(). Keys can be removed from the KeyStore using the deleteEntry() method.
Currently, only two types of keys can be stored in the ProtectToolkit-J KeyStore: either ProtectToolkit-J keys or javax.crypto.spec.SecretKeySpec keys. Other key types must be converted to their ProtectToolkit-J equivalents before storage.
Currently, the Certificate support is based on Sun’s Certificate implementation which is only available on the Sun Java2 JVM.
Per Key password protection is not supported, so a null password can be supplied to the methods used to store and retrieve keys from the KeyStore. The password provided to the load() method will be used to log on to the token, and so to access private objects on the token it is necessary to provide the PIN. If a PIN is not supplied, all objects will be stored as public objects. When a PIN is supplied, only PublicKey and Certificate objects will be stored as public objects; all others will be private. In either case, the InputStream passed to the store() and load() methods will not change the contents of the key store.
Keys stored in the KeyStore are the only thread-safe ProtectToolkit-J keys. A key instance obtained from the KeyStore.getKeyEntry() method will return a key that can be used in multiple Cipher, MAC, and Signature instances.
The following example will create a new random DES key, and then store that key in the KeyStore. Note that even though we first create the key and then store it, the actual key value will not leave the hardware and therefore remains secure.
KeyGenerator keyGen = KeyGenerator.getInstance(“DES”, “SAFENET”);
Key key = keyGen.generateKey();
KeyStore keyStore = KeyStore.getInstance(“CRYPTOKI”, “SAFENET”);
keyStore.load(null, null);
keyStore.setKeyEntry(“des key”, key, null, null);
The following example can be used to access the previously stored key:
KeyStore keyStore = KeyStore.getInstance(“CRYPTOKI”, “SAFENET”);
keyStore.load(null, null);
Key key = keyStore.getKey(“des key”, null);
Key wrapping
The CRYPTOKI KeyStore also provides a key wrapping mechanism. Key wrapping is a technique where one key value is encrypted using another key. With ProtectToolkit-J, since the key values are stored securely on the hardware, we can use this technique to encrypt the key on the hardware and then extract the encrypted key.
For example, using this mechanism, a session key can be generated on the hardware and then exported from the hardware in an encrypted (wrapped) form. The key will generally be encrypted using a Public/Private key encryption cipher and can then be safely exported from the HSM. It is also possible to use secret keys for key wrapping. In this case, however, the same secret key must exist on both the source (performing the wrapping function) and the destination adapters.
The WrappingKeyStore API is an extension to the standard JCE that is used to provide access to key wrapping services. This class is identical to the standard KeyStore API, except that it provides wrapKey() and unwrapKey() methods. The wrapping key store can be instantiated using the following code:
import au.com. safenet.crypto.WrappingKeyStore;
...
WrappingKeyStore wks = WrappingKeyStore.getInstance("CRYPTOKI",
"SAFENET");
...
The wrapKey() method has the following signature:
public byte[] wrapKey(Key wrapKey, String transformation, Key key)
throws GeneralSecurityException
The wrapKey parameter specifies the Key used to encrypt the key parameter. The transformation parameter specifies the encryption transformation that is to be used to encrypt the key. With the CRYPTOKI KeyStore, you can transform the following:
-
AESWrap
-
AESWrapPad
-
RSA/ECB/PKCS1Padding
-
RSA/ECB/NoPadding
-
DES/ECB/NoPadding
-
DES/ECB/PKCS5Padding
-
DESede/ECB/NoPadding
-
DESede/ECB/PKCS5Padding
-
IDEA/ECB/NoPadding
-
IDEA/ECB/PKCS5Padding
-
CAST128/ECB/NoPadding
-
CAST128/ECB/PKCS5Padding
-
RC2/ECB/NoPadding
-
RC2/ECB/PKCS5Padding
-
RC4
A GeneralSecurityException will be thrown if the transformation parameter is invalid.
The value returned is a byte array containing the encrypted key. This value can be passed to the unwrapKey() method to extract the original key. The unwrapKey() method has the following signature:
public Key unwrapKey(Key unwrapKey, String transformation,
byte[] wrappedKey, String keyAlgorithm)
throws GeneralSecurityException
This method will "unwrap" or decrypt the encrypted key using the provided decryption key and transformation. The Key returned will be of the type specified by the keyAlgorithm parameter. This parameter must match the actual key type that was originally wrapped.
The unwrapKey parameter should be either the same secret key as was used to wrap the key, or the private key corresponding to the public key used to wrap the key. The transformation parameter specifies the decryption transformation used to decrypt the key. This value should be the same as that used to wrap the key. The wrappedKey parameter should contain the encrypted key. The keyAlgorithm should specify the algorithm that the decrypted key is for.
A GeneralSecurityException will be thrown if the transformation parameter is invalid.
The following example will create a new random RC4 key, wrap that key with an RSA public key, and unwrap it with the associated RSA private key.
KeyGenerator keyGen = KeyGenerator.getInstance(“RC4”, “SAFENET”);
Key rc4Key = keyGen.generateKey();
WrappingKeyStore wks = WrappingKeyStore.getInstance(“CRYPTOKI”);
wks.load(null, null); // initialise the KeyStore
Key publicKey = wks.getKey(“RSA_pub”, null);
byte[] encKey = Wks.wrapKey(publicKey,“RSA/ECB/PKCS1Padding”,rc4Key);
// give the encrypted key to the recipient, and unwrap it
Key privateKey = wks.getKey(“RSA_priv”, null);
Key recoveredKey = wks.unwrapKey(privateKey, “RSA/ECB/PKCS1Padding’,
encKey);
Key specifications
As well as supporting the relevant JCA/JCE defined KeySpec classes, ProtectToolkit-J includes a number of custom provider-independent key classes for use with its KeyFactory classes. These classes all live in the au.com.safenet.crypto.spec package:
AsciiEncodedKeySpec
Used to encode RSA, DSA or Diffie-Hellman public and private keys as ASCII strings. These strings contain the key's integer components as hexadecimal strings separated by a full stop. For example, an RSA private key:
public_exponent.modulus.private_exponent.p.q
A public key will contain only the first two elements and a private key will contain all five. The RSA KeyFactory can convert from this KeySpec into the provider-based key.
For DSA keys the format is:
y.p.q.g (private keys) x.p.q.g (public keys)
For Diffie-Hellman keys, the format is:
y.p.g (private keys) x.p.g (public keys)
CASTKeySpec
Used to encode keys for the CAST algorithm. This class takes a byte array, which it will use directly as the CAST key. The array must be less than or equal to 16 bytes, the maximum key size for a CAST key.
IDEAKeySpec
Used to encode keys for the IDEA algorithm. This class takes a byte array and uses the first 16 bytes of the array as the IDEA key.
RC2KeySpec
Used to encode keys for the RC2 algorithm. This class takes a byte array, which it will use directly as the RC2 key. The array must be less than or equal to 128 bytes, the maximum key size for a RC2 key.
RC4KeySpec
Used to encode keys for the RC4 algorithm. This class takes a byte array, which it will use directly as the RC4 key. The array must be less than or equal to 256 bytes, the maximum key size for a RC4 key.
AESKeySpec
Used to encode keys for the AES algorithm. This class takes a byte array, which it will use directly as the AES key. The array must be 16, 24 or 32 bytes.